#pragma once
#include <iostream>
#include <functional>
#include "Sock.hpp"
#include "Log.hpp"
#include "Error.hpp"
#include "Epoll.hpp"

using func_t = std::function<std::string(std::string)>;

static const uint16_t defaultport = 8888;

static const int gnums = 1024;

class EpollServer
{
public:
    EpollServer(func_t func,uint16_t port = defaultport) :_func(func), _port(port)
    {
    }
    ~EpollServer()
    {
        _listensock.Close();
        _epoll.Close();
    }
    void InitServer()
    {
        // 1.建立tcp通信
        // 1.1 创建套接字
        _listensock.Socket();
        // 1.2 绑定端口
        _listensock.Bind(_port);
        // 1.3 监听
        _listensock.Listen();
        // 2.创建epoll模型
        _epoll.Create();
    }
    void Start()
    {
        // 能进行accept吗？
        // 不能需要让epoll通知我们事件就绪
        // 我们可以将epoll封装一下
        // 让epoll关心listensock
        uint32_t events = EPOLLIN;
        _epoll.AddModEvent(EPOLL_CTL_ADD, _listensock.Fd(), events);
        while (true)
        {
            int timeout = 1000; // 单位是毫秒
            // epoll_wait的返回值是 就绪事件的个数
            int n = _epoll.Wait(_revs, gnums, timeout);
            switch (n)
            {
            case 0:
                logMessage(Debug, "no events ready...");
                break;
            case -1:
                logMessage(Warning, "epoll_wait filed...");
                break;
            default:
                logMessage(Info, "有%d个事件就绪\n", n);
                HandEvent(n);
                break;
            }
        }
    }
    void Accepter()
    {
        std::string clientip;
        uint16_t clientport;
        int sock = _listensock.Accept(clientip, clientport);
        if(sock < 0)
            return;
        // 一定是一个正确的sock
        // 将sock放入epoll模型中
        _epoll.AddModEvent(EPOLL_CTL_ADD, sock, EPOLLIN);
    }
    void Recver(int fd)
    {
        char buf[1024];
        int n = recv(fd, buf, sizeof(buf) - 1, 0);
        if (n > 0)
        {
            // 把\n 替换成 \0

            buf[n - 1] = 0;
            std::cout << "client# " << buf << std::endl;

            // 业务处理

            // 直接写回去
            std::string sendBuf = "server# ";
            // sendBuf += buf;
            // send(fd, sendBuf.c_str(), sendBuf.size(), 0);

            sendBuf += _func(buf);
            send(fd, sendBuf.c_str(), sendBuf.size(), 0);
            
        }
        else
        {
            if (n == 0)
                logMessage(Info,"peer is close, sock = %d",fd);
            else
                logMessage(Warning,"read sock = %d failed...",fd);
            // 出现异常后都需要在epoll模型中删除 对应的fd
            // 并且关掉对应的文件描述符
            _epoll.DelEvent(fd);
            close(fd);
        }
    }
    void HandEvent(int n)
    {
        for (int i = 0; i < n; i++)
        {
            int fd = _revs[i].data.fd;
            uint32_t events = _revs[i].events;
            logMessage(Info,"当前正在处理%d上的%s",fd,(events & EPOLLIN) ? "EPOLLIN" :"OTHER");
            // 读事件就绪
            if (events == EPOLLIN)
            {
                // 如果是监听套接字
                if (fd == _listensock.Fd())
                {
                    Accepter();
                }
                else
                {
                    Recver(fd);
                }
            }
            // 写事件就绪
            if (events == EPOLLOUT)
            {
                // TODO
            }
        }
    }



private:
    Sock _listensock;
    uint16_t _port;
    Epoller _epoll;
    // epoll模型中，当有事件就绪时，通过revs告知用户
    struct epoll_event _revs[gnums];
    func_t _func;
};